<template>
  <div class="ws-pv-client">
    <div class="header">
      <h2>光伏实时数据双向通信客户端（Vue2 版）</h2>
      <div class="btn-group">
        <el-button 
          type="primary" 
          @click="connect" 
          :disabled="isConnected"
          icon="el-icon-link"
        >
          建立连接
        </el-button>
        <el-button 
          type="danger" 
          @click="disconnect" 
          :disabled="!isConnected"
          icon="el-icon-unlink"
        >
          断开连接
        </el-button>
      </div>
    </div>

    <!-- 消息发送区域 -->
    <div class="send-area" v-if="isConnected">
      <el-input
        v-model="sendMessage"
        placeholder="输入发送消息（文本/JSON，如 {\"cmd\":\"queryPower\"}）"
        @keyup.enter="sendMessageToServer"
        clearable
      ></el-input>
      <el-button 
        type="success" 
        @click="sendMessageToServer"
        icon="el-icon-paper-plane"
        class="send-btn"
      >
        发送消息
      </el-button>
    </div>

    <!-- 日志区域 -->
    <div class="log-area">
      <h3>通信日志</h3>
      <div class="log-container" ref="logContainer">
        <div 
          v-for="(log, index) in logList" 
          :key="index"
          :class="`log-item log-${log.type}`"
        >
          <span class="log-time">[{{ log.time }}]</span>
          <span class="log-tag">{{ log.type === 'send' ? '发送' : log.type === 'receive' ? '接收' : '错误' }}</span>
          <span class="log-content">{{ log.content }}</span>
        </div>
      </div>
    </div>

    <!-- 光伏数据展示区域 -->
    <div class="data-card">
      <h3>光伏实时数据</h3>
      <div class="data-item">
        <label>总有功功率：</label>
        <span class="data-value">{{ totalActivePower }} kW</span>
      </div>
      <div class="data-item">
        <label>更新时间：</label>
        <span class="data-value">{{ updateTime }}</span>
      </div>
      <div class="data-item">
        <label>连接状态：</label>
        <span class="data-value" :class="isConnected ? 'status-connected' : 'status-disconnected'">
          {{ isConnected ? '已连接' : '未连接' }}
        </span>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'WebSocketPvClient',
  data() {
    return {
      // WebSocket 配置
      wsUrl: 'ws://10.168.1.146:8087/ws/iot/view', // 服务端地址（需修改）
      ws: null, // WebSocket 实例
      isConnected: false, // 连接状态

      // 消息相关
      sendMessage: '', // 待发送消息
      logList: [], // 通信日志列表

      // 光伏数据
      totalActivePower: '--', // 总有功功率
      updateTime: '--' // 数据更新时间
    }
  },
  destroyed() {
    // 组件销毁时断开连接，避免内存泄漏
    this.disconnect()
  },
  methods: {
    /**
     * 建立 WebSocket 连接
     */
    connect() {
      // 关闭现有连接（避免重复连接）
      if (this.ws) {
        this.ws.close()
      }

      // 创建 WebSocket 实例
      this.ws = new WebSocket(this.wsUrl)

      // 连接成功回调
      this.ws.onopen = () => {
        this.isConnected = true
        this.addLog('success', '连接成功，可发送消息和接收实时数据')
        this.$message.success('WebSocket 连接成功！')
      }

      // 接收服务端消息
      this.ws.onmessage = (event) => {
        const rawData = event.data
        this.addLog('receive', `收到数据：${rawData}`)
        this.parsePvData(rawData) // 解析光伏数据
      }

      // 连接错误回调
      this.ws.onerror = (error) => {
        const errorMsg = error.message || '未知错误'
        this.addLog('error', `连接错误：${errorMsg}`)
        this.$message.error(`连接错误：${errorMsg}`)
        this.resetState()
      }

      // 连接关闭回调
      this.ws.onclose = (event) => {
        this.addLog('error', `连接关闭：状态码 ${event.code}，原因：${event.reason || '无'}`)
        this.$message.warning('WebSocket 连接已关闭')
        this.resetState()
      }
    },

    /**
     * 断开 WebSocket 连接
     */
    disconnect() {
      if (this.ws) {
        this.ws.close()
        this.ws = null
      }
      this.resetState()
    },

    /**
     * 重置状态（连接断开时）
     */
    resetState() {
      this.isConnected = false
      this.sendMessage = ''
      this.totalActivePower = '--'
      this.updateTime = '--'
    },

    /**
     * 向服务端发送消息
     */
    sendMessageToServer() {
      const message = this.sendMessage.trim()
      if (!message) {
        this.$message.warning('请输入要发送的消息！')
        return
      }

      try {
        // 支持文本和 JSON 格式发送
        const isJson = message.startsWith('{') && message.endsWith('}')
        if (isJson) {
          // 验证 JSON 格式合法性
          JSON.parse(message)
          this.ws.send(message)
          this.addLog('send', `发送 JSON 消息：${message}`)
        } else {
          this.ws.send(message)
          this.addLog('send', `发送文本消息：${message}`)
        }
        this.sendMessage = '' // 清空输入框
      } catch (e) {
        this.addLog('error', `发送失败：${e.message}`)
        this.$message.error(`发送失败：${e.message}`)
      }
    },

    /**
     * 解析服务端返回的光伏数据
     * @param {string} rawData - 服务端原始数据
     */
    parsePvData(rawData) {
      try {
        // 尝试解析为 JSON 格式（推荐光伏数据格式）
        const jsonData = JSON.parse(rawData)
        // 更新总有功功率
        if (jsonData.totalActivePower !== undefined && !isNaN(jsonData.totalActivePower)) {
          this.totalActivePower = jsonData.totalActivePower.toFixed(3)
        }
        // 更新时间
        if (jsonData.time) {
          this.updateTime = jsonData.time
        } else {
          this.updateTime = this.formatTime(new Date())
        }
        // 服务端响应消息
        if (jsonData.message) {
          this.addLog('receive', `服务端响应：${jsonData.message}`)
        }
      } catch (e) {
        // 非 JSON 格式，处理纯文本/数字
        const power = parseFloat(rawData)
        if (!isNaN(power)) {
          // 纯数字默认作为总有功功率
          this.totalActivePower = power.toFixed(3)
          this.updateTime = this.formatTime(new Date())
        } else {
          this.addLog('receive', `服务端文本消息：${rawData}`)
        }
      }
    },

    /**
     * 添加通信日志
     * @param {string} type - 日志类型：send/receive/error/success
     * @param {string} content - 日志内容
     */
    addLog(type, content) {
      const log = {
        type: type,
        content: content,
        time: this.formatTime(new Date())
      }
      this.logList.push(log)
      // 滚动到最新日志
      this.$nextTick(() => {
        const logContainer = this.$refs.logContainer
        logContainer.scrollTop = logContainer.scrollHeight
      })
      // 限制日志数量（最多保留100条，避免性能问题）
      if (this.logList.length > 100) {
        this.logList.shift()
      }
    },

    /**
     * 格式化时间
     * @param {Date} date - 日期对象
     * @returns {string} 格式化后的时间字符串
     */
    formatTime(date) {
      return date.toLocaleString('zh-CN', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit'
      })
    }
  }
}
</script>

<style scoped>
.ws-pv-client {
  width: 1000px;
  margin: 20px auto;
  font-family: 'Arial', sans-serif;
  color: #333;
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding-bottom: 10px;
  border-bottom: 1px solid #eee;
}

.btn-group {
  display: flex;
  gap: 10px;
}

.send-area {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
}

.send-area .el-input {
  flex: 1;
}

.send-btn {
  white-space: nowrap;
  width: 100px;
}

.log-area {
  margin-bottom: 20px;
}

.log-container {
  height: 250px;
  border: 1px solid #e6e6e6;
  border-radius: 4px;
  padding: 10px;
  overflow-y: auto;
  background-color: #fafafa;
}

.log-item {
  margin-bottom: 8px;
  padding: 6px 10px;
  border-radius: 3px;
  line-height: 1.5;
}

.log-send {
  background-color: #e8f4f8;
  border-left: 3px solid #409eff;
}

.log-receive {
  background-color: #f0f9eb;
  border-left: 3px solid #67c23a;
}

.log-error {
  background-color: #fef0f0;
  border-left: 3px solid #f56c6c;
}

.log-time {
  color: #999;
  font-size: 12px;
  margin-right: 8px;
}

.log-tag {
  display: inline-block;
  width: 40px;
  text-align: center;
  font-size: 12px;
  font-weight: bold;
  margin-right: 8px;
}

.log-send .log-tag {
  color: #409eff;
}

.log-receive .log-tag {
  color: #67c23a;
}

.log-error .log-tag {
  color: #f56c6c;
}

.log-content {
  font-size: 14px;
}

.data-card {
  border: 1px solid #e6e6e6;
  border-radius: 8px;
  padding: 20px;
  background-color: #fafafa;
}

.data-card h3 {
  margin-bottom: 15px;
  padding-bottom: 10px;
  border-bottom: 1px solid #eee;
}

.data-item {
  display: flex;
  align-items: center;
  margin-bottom: 10px;
}

.data-item label {
  width: 100px;
  font-weight: 500;
  color: #666;
}

.data-value {
  font-size: 15px;
}

.status-connected {
  color: #67c23a;
  font-weight: bold;
}

.status-disconnected {
  color: #f56c6c;
}
</style>